JUnit 5, the latest version of the popular Java testing framework, introduces several new features and enhancements to help developers write efficient and robust unit tests. One such notable addition is dynamic tests. Unlike traditional static tests, dynamic tests allow for the creation of tests at runtime, enabling developers to write more flexible and expressive test cases. In this article, we will explore the concept of dynamic tests in JUnit 5 and learn how to leverage their capabilities to write comprehensive and adaptable unit tests.
On this article, we will write some test cases for our Document
class.
public record Document(String documentId,
int numberOfPages,
LocalDate documentDate,
String author) {
public boolean hasDocumentExpired() {
return documentDate.isBefore(LocalDate.now());
}
public String documentId() {
return documentId.toUpperCase();
}
}
The document class has two methods hasDocumentExpired
and documentId
which returns the document id as upper case.
Since it’s a good practice to keep test small as possible, there would be two tests needed to cover those two methods, which would look like this.
public class StaticDocumentTests {
@Test
@DisplayName("Document should be expired if the document date is before today's date")
void testDocumentExpiration() {
var document = new Document("document-123", 23,
LocalDate.now().minusWeeks(2), "Defrim Hasani");
assertThat(document.hasDocumentExpired()).isTrue();
}
@Test
@DisplayName("Document id should be all upper case")
void testDocumentId() {
var document = new Document("document-123", 23,
LocalDate.now().minusWeeks(2), "Defrim Hasani");
assertThat(document.documentId()).isUpperCase();
}
}
The tests are fine, they work as expected. But, as you can see on both tests we had to create an instance of the document and run assertions against it by creating methods for each case we want to test.
However, using junit5 we now can create dynamic tests that can be created at runtime as part of a factory method.
After rewriting our test class and apply this feature, it looks now like this.
public class DynamicDocumentTests {
@TestFactory
@DisplayName("Dynamic test cases")
List<DynamicTest> documentDynamicTests(){
var document = new Document("document-123", 23,
LocalDate.now().minusWeeks(2), "Defrim Hasani");
return Arrays.asList(
DynamicTest.dynamicTest("Document should be expired if the document date is before today's date",
() -> assertThat(document.hasDocumentExpired()).isTrue()),
DynamicTest.dynamicTest("Document id should be all upper case",
() -> assertThat(document.documentId()).isUpperCase())
);
}
}
Amazing right? — With just one java method, we created multiple tests and also reused the same instance of the document.